﻿using System;
using System.Collections;
using System.Collections.Generic;

namespace DimensionsHelper.Common.Contracts.Metadata;

/// <summary>
///     不限制元素类型的元数据对象集合。为了保护内部对象内部逻辑，此接口不提供在外部修改集合元素的方法。
/// </summary>
public interface IMetadataObjectCollection : IEnumerable
{
    /// <summary>
    ///     获取已删除的对象序列。
    /// </summary>
    IEnumerable DeletedItems { get; }

    /// <summary>
    ///     删除对象列表长度。
    /// </summary>
    int DeletedItemsCount { get; }


    /// <summary>
    ///     当前集合的元素数量。
    /// </summary>
    int Count { get; }

    /// <summary>
    ///     第一个成员对象
    /// </summary>
    object FirstObject { get; }

    /// <summary>
    ///     获取指定索引的集合元素。
    /// </summary>
    /// <param name="index">给定数字索引，0开始</param>
    /// <returns>指定索引位置的集合对象，如果给定索引不在当前集合的有效范围内，返回null</returns>
    /// <exception cref="IndexOutOfRangeException" />
    object Get(int index);

    /// <summary>
    ///     获取第一个类型是<typeparamref name="T" />并且符合<paramref name="predicate" />回调函数的元素。
    /// </summary>
    /// <typeparam name="T">查找类型</typeparam>
    /// <param name="predicate">断言函数</param>
    /// <returns>如果成功查找到，返回第一个符合的结果，否则，返回null。</returns>
    T? Find<T>(Predicate<T> predicate);

    /// <summary>
    ///     尝试获取集合中第一个类型是<typeparamref name="T" />并且符合<paramref name="predicate" />回调函数的元素。
    /// </summary>
    /// <typeparam name="T">查找类型</typeparam>
    /// <param name="predicate">断言函数</param>
    /// <param name="result">查找的结果</param>
    /// <returns>如果查找到了，返回true，否则，返回false</returns>
    bool TryFind<T>(Predicate<T> predicate, out T? result);

    /// <summary>
    ///     计算集合中类型是<typeparamref name="T" />并且符合<paramref name="predicate" />回调函数的元素数量。
    /// </summary>
    /// <typeparam name="T">查找类型</typeparam>
    /// <param name="predicate">断言函数</param>
    /// <returns>符合条件的元素数量</returns>
    int CountIf<T>(Predicate<T> predicate);
}


/// <summary>
///     元数据可命名对象的集合，不允许外部修改。
/// </summary>
/// <typeparam name="T">此类型需要实现<see cref="INamedObject" />接口</typeparam>
public interface IMetadataStringKeyCollection<T> : 
    IMetadataObjectCollection, IEnumerable<T> where T : class
{
    /// <summary>
    ///     获取指定索引的成员对象，如果索引无效，应当抛出错误。
    /// </summary>
    /// <param name="index">指定索引，需要大于等于0并小于当前集合元素数量。</param>
    /// <returns>指定索引的成员对象。</returns>
    /// <exception cref="IndexOutOfRangeException"></exception>
    T this[int index] { get; }

    /// <summary>
    ///     创建一个新的成员对象，不添加进当前集合。
    /// </summary>
    /// <param name="key">指定关键字</param>
    /// <returns></returns>
    T CreateObject(string key);

    /// <summary>
    ///     判断指定名称是否存在于当前集合中。
    /// </summary>
    /// <param name="key">给定关键字，不区分大小写。</param>
    /// <returns>如果已存在，返回true，否则，返回false。</returns>
    bool Exists(string key);

    /// <summary>
    ///     获取指定名称的成员对象。
    /// </summary>
    /// <param name="key">给定变量名，不区分大小写。</param>
    /// <returns>查找到的对象，如果不存在，将创建一个新的对象，并添加进集合末尾。</returns>
    T GetByKey(string key);

    /// <summary>
    ///     尝试查找指定名称的对象。
    /// </summary>
    /// <param name="key">给定变量名，不区分大小写。</param>
    /// <param name="value">查找到的对象，如果不存在，此值为null。</param>
    /// <returns>如果给定名称存在，返回true，否则，返回false。</returns>
    bool TryGetByKey(string key, out T value);
}


/// <summary>
///     分上下文类型存储的对象集合，不提供外部修改集合的方法。
/// </summary>
/// <typeparam name="T"></typeparam>
public interface IMetadataContextCollection<T> : IMetadataStringKeyCollection<T>, IMetadataObject
    where T : class, IMetadataContextObject
{
    /// <summary>
    ///     创建新的对象，不添加进当前集合。
    /// </summary>
    /// <param name="name">对象名</param>
    /// <param name="context">上下文类型</param>
    /// <returns></returns>
    T CreateObject(string name, string context);

    /// <summary>
    ///     获取指定名称和上下文下的对象。
    /// </summary>
    /// <param name="name">对象名</param>
    /// <param name="context">上下文类型</param>
    /// <returns>如果给定对象存在，返回已有对象，否则，创建一个新的并返回</returns>
    T Get(string name, string context);

    /// <summary>
    ///     判断给定名称在给定上下文下是否存在。
    /// </summary>
    /// <param name="name">对象名</param>
    /// <param name="context">上下文类型</param>
    bool Exists(string name, string context);

    /// <summary>
    ///     筛选指定上下文类型的成员对象。
    /// </summary>
    /// <param name="context">给定上下文类型</param>
    IEnumerable<T> Filter(string context);

    /// <summary>
    ///     获取集合中指定上下文类型的对象数量。
    /// </summary>
    /// <param name="context">给定上下文类型</param>
    /// <returns>集合中符合上下文类型的对象数</returns>
    int CountIf(string context);
}


/// <summary>
///     带有描述的元数据对象集合。
/// </summary>
/// <typeparam name="T"></typeparam>
public interface IMetadataLabeledCollection<T> : IMetadataStringKeyCollection<T>, IMetadataLabeledObject
    where T : class
{
}